<template>
  <div>
    <div id="map"
         class="map"></div>
    <div id='operate-div'>
      <el-button round
                 @click="panToLondon">伦敦</el-button>
      <el-button type="primary"
                 @click="elaticToMoscow"
                 round>莫斯科</el-button>
      <el-button type="success"
                 @click="flyToBern"
                 round>伯尔尼</el-button>
      <el-select v-model="baseMapSelection"
                 placeholder="底图">
        <el-option v-for="item in baseMapSelections"
                   :key="item.value"
                   :label="item.label"
                   :value="item.value">
        </el-option>
      </el-select>
      <el-select v-model="overlayMapSelection"
                 placeholder="覆盖图">
        <el-option v-for="item in overlayMapSelections"
                   :key="item.value"
                   :label="item.label"
                   :value="item.value">
        </el-option>
      </el-select>
      <el-select v-model="viewProjectionSelection"
                 placeholder="视图投影">
        <el-option v-for="item in viewProjectionSelections"
                   :key="item.value"
                   :label="item.label"
                   :value="item.value">
        </el-option>
      </el-select>
    </div>
  </div>
</template>
<script>

import Map from 'ol/Map.js';
import View from 'ol/View.js';
import { easeIn, easeOut } from 'ol/easing.js';
import TileLayer from 'ol/layer/Tile.js';
import { fromLonLat } from 'ol/proj.js';
import { OSM, TileImage, TileWMS, XYZ, Vector as VectorSource } from 'ol/source.js';
import 'ol/ol.css';
import Feature from 'ol/Feature';
import Point from 'ol/geom/Point';
import VectorLayer from 'ol/layer/Vector';
import Select from 'ol/interaction/Select';
import { Style, Icon, Image as ImageStyle } from 'ol/style';
import { defaults as defaultControls, FullScreen } from 'ol/control.js';
import icon from '../../assets/icon.png';
import proj4 from 'proj4';
import { register } from 'ol/proj/proj4';
import { get as getProjection } from 'ol/proj';
import WMTS, { optionsFromCapabilities } from 'ol/source/WMTS';
import WMTSCapabilities from 'ol/format/WMTSCapabilities';
import { getWidth, getCenter } from 'ol/extent';
import TileGrid from 'ol/tilegrid/TileGrid';

export default {
  data () {
    return {
      map: null,
      baseMapSelection: '',
      baseMapSelections: [{ label: 'OSM (EPSG:3857)', value: 'osm' },
      { label: 'WMS (EPSG:4326)', value: 'wms4326' }
      ],
      overlayMapSelection: '',
      overlayMapSelections: [
        { label: 'British National Grid (EPSG:27700)', value: 'bng' },
        { label: 'Swisstopo WMS (EPSG:21781)', value: 'wms21781' },
        { label: 'NASA Arctic WMTS (EPSG:3413)', value: 'wmts3413' },
      ],
      viewProjectionSelection: '',
      viewProjectionSelections: [{ label: 'Spherical Mercator (EPSG:3857)', value: 'EPSG:3857' },
      { label: 'WGS 84 (EPSG:4326)', value: 'EPSG:4326' },
      { label: 'Mollweide (ESRI:54009)', value: 'ESRI:54009' }
      ],
      layers: null,
    }
  },
  methods: {
    //注册投影
    registerProj () {
      proj4.defs('EPSG:27700', '+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 ' +
        '+x_0=400000 +y_0=-100000 +ellps=airy ' +
        '+towgs84=446.448,-125.157,542.06,0.15,0.247,0.842,-20.489 ' +
        '+units=m +no_defs');
      proj4.defs('EPSG:23032', '+proj=utm +zone=32 +ellps=intl ' +
        '+towgs84=-87,-98,-121,0,0,0,0 +units=m +no_defs');
      proj4.defs('EPSG:5479', '+proj=lcc +lat_1=-76.66666666666667 +lat_2=' +
        '-79.33333333333333 +lat_0=-78 +lon_0=163 +x_0=7000000 +y_0=5000000 ' +
        '+ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +units=m +no_defs');
      proj4.defs('EPSG:21781', '+proj=somerc +lat_0=46.95240555555556 ' +
        '+lon_0=7.439583333333333 +k_0=1 +x_0=600000 +y_0=200000 +ellps=bessel ' +
        '+towgs84=674.4,15.1,405.3,0,0,0,0 +units=m +no_defs');
      proj4.defs('EPSG:3413', '+proj=stere +lat_0=90 +lat_ts=70 +lon_0=-45 +k=1 ' +
        '+x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs');
      proj4.defs('EPSG:2163', '+proj=laea +lat_0=45 +lon_0=-100 +x_0=0 +y_0=0 ' +
        '+a=6370997 +b=6370997 +units=m +no_defs');
      proj4.defs('ESRI:54009', '+proj=moll +lon_0=0 +x_0=0 +y_0=0 +datum=WGS84 ' +
        '+units=m +no_defs');
      register(proj4);
    },
    //初始化底图
    initLayers () {
      var layers = {};
      layers['bng'] = new TileLayer({
        source: new XYZ({
          projection: 'EPSG:27700',
          url: 'https://tileserver.maptiler.com/miniscale/{z}/{x}/{y}.png',
          crossOrigin: '',
          maxZoom: 6
        })
      });

      layers['osm'] = new TileLayer({
        source: new OSM()
      });
      layers['wms4326'] = new TileLayer({
        source: new TileWMS({
          url: 'https://ahocevar.com/geoserver/wms',
          crossOrigin: '',
          params: {
            'LAYERS': 'ne:NE1_HR_LC_SR_W_DR',
            'TILED': true
          },
          projection: 'EPSG:4326'
        })
      });

      layers['wms21781'] = new TileLayer({
        source: new TileWMS({
          attributions: '© <a href="http://www.geo.admin.ch/internet/geoportal/' +
            'en/home.html">Pixelmap 1:1000000 / geo.admin.ch</a>',
          crossOrigin: 'anonymous',
          params: {
            'LAYERS': 'ch.swisstopo.pixelkarte-farbe-pk1000.noscale',
            'FORMAT': 'image/jpeg'
          },
          url: 'https://wms.geo.admin.ch/',
          projection: 'EPSG:21781'
        })
      });
      var parser = new WMTSCapabilities();
      var url = 'https://map1.vis.earthdata.nasa.gov/wmts-arctic/' +
        'wmts.cgi?SERVICE=WMTS&request=GetCapabilities';
      fetch(url).then(function (response) {
        return response.text();
      }).then(function (text) {
        var result = parser.read(text);
        var options = optionsFromCapabilities(result, {
          layer: 'OSM_Land_Mask',
          matrixSet: 'EPSG3413_250m'
        });
        options.crossOrigin = '';
        options.projection = 'EPSG:3413';
        options.wrapX = false;
        layers['wmts3413'] = new TileLayer({
          source: new WMTS(/** @type {!module:ol/source/WMTS~Options} */(options))
        });
      });

      layers['grandcanyon'] = new TileLayer({
        source: new XYZ({
          url: 'https://tileserver.maptiler.com/grandcanyon@2x/{z}/{x}/{y}.png',
          crossOrigin: '',
          tilePixelRatio: 2,
          maxZoom: 15,
          attributions: 'Tiles © USGS, rendered with ' +
            '<a href="http://www.maptiler.com/">MapTiler</a>'
        })
      });

      var startResolution =
        getWidth(getProjection('EPSG:3857').getExtent()) / 256;
      var resolutions = new Array(22);
      for (var i = 0, ii = resolutions.length; i < ii; ++i) {
        resolutions[i] = startResolution / Math.pow(2, i);
      }

      layers['states'] = new TileLayer({
        source: new TileWMS({
          url: 'https://ahocevar.com/geoserver/wms',
          crossOrigin: '',
          params: { 'LAYERS': 'topp:states' },
          serverType: 'geoserver',
          tileGrid: new TileGrid({
            extent: [-13884991, 2870341, -7455066, 6338219],
            resolutions: resolutions,
            tileSize: [512, 256]
          }),
          projection: 'EPSG:3857'
        })
      });
      this.layers = layers;
    },
    //初始化图层
    initMap () {
      this.map = new Map({
        layers: [
          layers['osm'],
          layers['bng']
        ],
        target: 'map',
        view: new View({
          projection: 'EPSG:3857',
          center: [0, 0],
          zoom: 2
        })
      });
    },
    panToLondon () {
      var london = fromLonLat([-0.12755, 51.507222]);
      this.map.getView().animate({ center: london, duration: 2000 });
    },
    elaticToMoscow () {
      var moscow = fromLonLat([37.6178, 55.7517]);
      this.map.getView().animate({ center: moscow, duration: 2000, easing: this.elastic });
    },
    elastic (t) {
      return Math.pow(2, -10 * t) * Math.sin((t - 0.075) * (2 * Math.PI) / 0.3) + 1;
    },
    flyToBern () {
      var bern = fromLonLat([7.4458, 46.95]);
      this.flyTo(bern, function () { });
    },
    flyTo (location, done) {
      var duration = 2000;
      var view = this.map.getView();
      var zoom = view.getZoom();
      var parts = 2;
      var called = false;
      function callback (complete) {
        --parts;
        if (called) {
          return;
        }
        if (parts === 0 || !complete) {
          called = true;
          done(complete);
        }
      }
      view.animate({
        zoom: zoom - 1,
        duration: duration / 2
      }, {
          zoom: zoom,
          duration: duration / 2
        }, callback);
      view.animate({
        center: location,
        duration: duration
      }, callback);
    },
    setIconStyle (src, img) {
      return new Style({
        image: new Icon(/** @type {module:ol/style/Icon~Options} */({
          anchor: [0.5, 0.96],
          crossOrigin: 'anonymous',
          src: src,
          img: img,
          imgSize: img ? [img.width, img.height] : undefined
        }))
      });
    }
  },
  mounted () {
    var istanbul = fromLonLat([28.9744, 41.0128]);
    var feature = new Feature(new Point(istanbul));
    feature.set('style', this.setIconStyle(icon));
    var view = new View({
      center: istanbul,
      zoom: 6
    });
    var vectorLayer = new VectorLayer({
      source: new VectorSource({
        features: [feature]
      }),
      style: function (f) {
        return f.get('style');
      }
    });
    var map = this.map = new Map({
      controls: defaultControls().extend([new FullScreen()]),
      target: 'map',
      layers: [
        new TileLayer({
          preload: 4,
          source: new OSM()
        }),
        vectorLayer
      ],
      // Improve user experience by loading tiles while animating. Will make
      // animations stutter on mobile or slow devices.
      loadTilesWhileAnimating: true,
      view: view
    });
    var selectStyle = {};
    var select = new Select({
      style: feature => {
        var image = feature.get('style').getImage().getImage();
        if (!selectStyle[image.src]) {
          //canvas操作
          var canvas = document.createElement('canvas');
          var context = canvas.getContext('2d');
          canvas.width = image.width;
          canvas.height = image.height;
          context.drawImage(image, 0, 0, image.width, image.height);
          var imageData = context.getImageData(0, 0, canvas.width, canvas.height);
          var data = imageData.data;
          console.log(data);
          for (var i = 0, ii = data.length; i < ii; i = i + (i % 4 == 2 ? 2 : 1)) {
            data[i] = 255 - data[i];
          }
          context.putImageData(imageData, 0, 0);
          selectStyle[image.src] = this.setIconStyle(undefined, canvas);
        }
        return selectStyle[image.src];
      }
    });
    map.addInteraction(select);
    map.on('pointermove', function (evt) {
      map.getTargetElement().style.cursor =
        map.hasFeatureAtPixel(evt.pixel) ? 'pointer' : '';
    });
  },
}
</script>
<style lang="scss" scoped>
#map {
  height: 800px;
}
#operate-div {
  position: absolute;
  bottom: 20px;
}
.map:-moz-full-screen {
  height: 100%;
}
.map:-webkit-full-screen {
  height: 100%;
}
.map:-ms-fullscreen {
  height: 100%;
}
.map:fullscreen {
  height: 100%;
}
.ol-rotate {
  top: 3em;
}
</style>
